    package multiNyID.Detector;
/*
 * class DetectMarkersNyID
 *
 * bikin kelas untuk memproses aksi yang dimiliki tiapmarker yang terdeteksi oleh kelas MarkerDetectorNyID
 * --------------------------------------------------------------------------------
 * Based On NyARToolkit The Java edition ARToolKit class library.
 * modified from class DetectMarkers - Andrew Davison [ad@fivedots.coe.psu.ac.th]
 *
 * @author whe_green@yahoo.co.id
 * Analisis Metode Occlusion Based Pada Augmented Reality
 * Studi Kasus Interaksi dengan Objek Virtual Secara Realtime
 * Menggunakan Gerakan Tangan
 *
 * Institut Teknologi Telkom
 * Fakultas Informatika 2007
 * Bandung Indonesia
 *
 * nyargreen.wordpress.com
 */
import multiNyID.MarkerModel.MarkerModelNyID;
import multiNyID.MarkerModel.MarkerGroup;
import multiNyID.Interaksi.DemoOcclusion;
import multiNyID.Objek.fpsCounter;
import java.util.*;

import javax.vecmath.*;

import jp.nyatla.nyartoolkit.java3d.utils.*;

import jp.nyatla.nyartoolkit.NyARException;
import jp.nyatla.nyartoolkit.core.param.NyARParam;
import jp.nyatla.nyartoolkit.core.transmat.NyARTransMatResult;
import jp.nyatla.nyartoolkit.nyidmarker.data.NyIdMarkerDataEncoder_RawBit;
import multiNyID.Interaksi.InteraksiInterface;
import multiNyID.Main.MainInterface;
import multiNyID.Main.MultiNyID;

public class DetectMarkersNyID
{
//  private final static double MIN_CONF = 0.5;
//                // smallest confidence accepted for finding a marker
//
//  private final static int CONF_SIZE = 1000;
//               // for converting confidence level double <--> integer

  private final static int MAX_NO_DETECTIONS = 30;
               // number of times a marker goes undetected before being made invisible

  private ArrayList<MarkerGroup> markerGroups;

  private int numMarkers;

//  private MultiNyID top;    // for reporting status
  private MainInterface top;    // for reporting status
  private MarkerDetectorNyID detector;

  private NyARTransMatResult transMat = new NyARTransMatResult();
  private Matrix4d posRata;
     // transformation matrix for a marker, which is used to move its model
  private int pointer1=0;
  private int pointer2=0;

  private int numGroupModel = 0; //jumlah group dalam arraylist

  private InteraksiInterface occDetect; //untuk deteksi occlusion dan action nya

  private fpsCounter fpsCount;

//  public DetectMarkersNyID(MultiNyID top)
  public DetectMarkersNyID(MainInterface top, InteraksiInterface interaksi)
  { 
    this.top = top;
//    markerModels = new ArrayList<MarkerModel>();
    markerGroups = new ArrayList<MarkerGroup>();
    numMarkers = 0;
    numGroupModel = 0;
    posRata = new Matrix4d();
    occDetect = interaksi;
    fpsCount = new fpsCounter();
  }  // end of DetectMarkersNyID()

  public void addMarkerGroup(MarkerGroup mg)
  { 
//    markerModels.add(numMarkers, mm);  // add to end of list
      markerGroups.add(numGroupModel, mg);  // add to end of list
      numMarkers = numMarkers + mg.getNumMarker();
      numGroupModel++;
  }
  public void createDetector(NyARParam params, J3dNyARRaster_RGB rasterRGB)
  // create a single detector for all the markers
  {
//    NyARCode[] markersInfo = new NyARCode[numMarkers];
    double[] widths = new double[numMarkers];
    int i = 0;
    ArrayList<MarkerModelNyID> markerModels = new ArrayList<MarkerModelNyID>();

    for(MarkerGroup mg : markerGroups){ //telusurmarkergroup
      markerModels = mg.getMm();
      for(MarkerModelNyID mm : markerModels){ //pindahin nyarcode ke markeinfo
//          markersInfo[i] = mm.get;
          widths[i] = mm.getMarkerWidth();
          i++;
          System.out.println("tes");
      }
      System.out.println("jumlah marker info="+i);
    }
    i--; //benerin jumlah i


//    for (MarkerModel mm : markerModels) {
//       markersInfo[i] = mm.getMarkerInfo();
//       widths[i] = mm.getMarkerWidth();
//       // System.out.println("Object " + i + ": marker info = " + markersInfo[i]);
//       i++;
//    }

    try {
      detector = new MarkerDetectorNyID(params, new NyIdMarkerDataEncoder_RawBit(), widths,
//                                         rasterRGB.getBufferReader().getBufferType());
                                         rasterRGB.getBufferType(), numMarkers);
//      detector.setContinueMode(false);   // no history stored; use SmoothMatrix instead
    }
    catch(NyARException e)
    {  System.out.println("Could not create markers detector");  
       System.exit(1);
    }
  }  // end of createDetector()



  public void updateModels(J3dNyARRaster_RGB rasterRGB)
  // move marker models using the detected marker positions inside the raster
  {

    int numDetections = getNumDetections(detector, rasterRGB);
    // System.out.println("numDetections: " + numDetections);

    try {
      StringBuffer statusInfo = new StringBuffer();   // for holding status information
        int idxMG = 0;
        int idxMM = 0;
        
        int jumMarker = 0;
        
        //buat nyimpen urutan pencarian marker dalam satu group
        int awal=0;
        int akhir=0;
        MarkerModelNyID ptr = null;
        MarkerModelNyID ptr2 = null;
        MarkerModelNyID grid = null;
        //------------------
        fpsCount.tick();
      for(MarkerGroup mg : markerGroups){ //telusur markergroup          
          posRata.setZero();
          jumMarker = 0;
          
          akhir = awal + mg.getNumMarker();
//          System.out.println("batas = "+awal+"-"+akhir);
//          System.out.println("\n group="+idxMG+"\n");
          Vector3d geser = new Vector3d();
          for(MarkerModelNyID mm : mg.getMm()){ //telusur markermodel di tiap markergroup
           
            int bestDetectedIdx = findBestDetectedIdx(detector, numDetections, mm.getNyID());   // look for mkIdx
            int mkIdx = -1;

                if (bestDetectedIdx == -1)   // marker not found so incr numTimesLost
                  mm.incrNumTimesLost();

                else  {   // marker found
                    mkIdx = detector.getNyID(bestDetectedIdx);
                    mm.resetNumTimesLost();
                    // apply the transformation from the detected marker to the marker's model
                    // System.out.println("  For markers list index " + mkIdx +
                    //                                ": best detected index = " + bestDetectedIdx);
                    detector.getTransmationMatrix(bestDetectedIdx, transMat);  //ambil nilai transmat dari tiap marker yang ke deteksi
                    if (transMat.has_value){
                                              
                          //dijumlahin dulu posisi dari beberapa marker yang mengacu untuk model - multi marker
                              Matrix4d mat = new Matrix4d(-transMat.m00, -transMat.m01, -transMat.m02, -transMat.m03,
                                                        -transMat.m10, -transMat.m11, -transMat.m12, -transMat.m13,
                                                         transMat.m20,  transMat.m21,  transMat.m22,  transMat.m23,
                                                         0,             0,             0,             1             );
                              //digeser untuk ke posisi tengah dulu
                              //code
                                 geser = mm.getPosisi();

                                 mat.setM03(geser.getX()+mat.getM03()); //M03 geser x
                                 mat.setM13(geser.getY()+mat.getM13()); //M13 geser y
                       
                              //code
                              posRata.add(mat); //hitung nilai sigma
                              jumMarker++;      //hitung jumlah matrik yang dijumlah

                    }
                    else
                          System.out.println("Problem with transformation matrix");
                      
                      // else // found a marker, but with low confidence
                      //  System.out.println("  ***** " + mkIdx + " conf: " + confidence);
                    }

                    if (mm.getNumTimesLost() > MAX_NO_DETECTIONS)   // marker not detected too many times
                      mm.hideModel();    // make its model invisible

                    statusInfo.append(mkIdx + ". NyID(" + mkIdx + ")\n");
                    addToStatusInfo(mm, statusInfo);

                    idxMM++;
                  } //akhir penelusurran marker model
                  //posisi dirata2 sejumlahmarker yang ke deteksi boi
//                  System.out.println("jumlah marker terdeteksi = "+jumMarker);
                  if (jumMarker > 0){

                    posRata.mul(1.0/jumMarker);
                    mg.getMarkerModel(0).moveModel(posRata);

                    //catur
                    if(mg.getMarkerModel(0).getNyID()==this.pointer2){
                        //pake void update pointer aja
                        ptr2 = mg.getMarkerModel(0);
                        
                    }
                    else
                        if(mg.getMarkerModel(0).getNyID() == this.pointer1)
                    {
                        //pake void update pointer aja
                        ptr = mg.getMarkerModel(0);
//                        System.exit(0);
                        
                    }
                    else{
                        grid = mg.getMarkerModel(0);
                        
                    }
//                    System.out.println("nyid = "+mg.getMarkerModel(0).getNyID());
                    }
          System.out.println("\n"); //batas loop
//          occDetect.indikatorPointer(grid, ptr, statusInfo);
          System.out.println("marker group ="+idxMG);
          occDetect.indikatorPointer(grid, ptr, ptr2, statusInfo);//catur

        System.out.println("marker group ="+idxMG);
          posRata.setZero();
          awal = awal + akhir;                   
          idxMG++;  
          } //akhir penelusuran markergroup
        
          top.setStatus( statusInfo.toString());   // display marker models status in the GUI
//          System.out.println(statusInfo);
    }
    catch(NyARException e)
    {  System.out.println(e);  }
   
  }  // end of updateModels()



  private int getNumDetections(MarkerDetectorNyID detector, J3dNyARRaster_RGB rasterRGB)
  {
    int numDetections = 0;
    try {
      synchronized (rasterRGB) {
        if (rasterRGB.hasData())
          numDetections = detector.detectMarkerLite(rasterRGB);
      }
    }
    catch(NyARException e)
    {  System.out.println(e);  }

    return numDetections;
  }  // end of getNumDetections()



  private int findBestDetectedIdx(MarkerDetectorNyID detector, int numDetections, int markerIdx)
  /* return best detected marker index for marker markerIdx from all detected markers,
     along with its confidence value as an integer */
  {
    int nyid = -1;
    int result = -1;
      for (int i = 0; i < numDetections; i++) {    // check all detected markers  
//      nyid = detector.generateNyid(detector.getMarker_data(i))-1;
        nyid = detector.getNyID(i);
//      System.out.println("detect"+i+" = "+nyid);
      if ((nyid == markerIdx)) {
        result = i;
//        System.out.println("\n------------------>result best detect"+i+" = "+nyid+"---"+markerIdx+"\n");
        break;
        
      }
    }
//    System.out.println("hasil pencarian - "+markerIdx+"-"+result);
    return result;
  }  // end of findBestDetectedIdx()


  private void addToStatusInfo(MarkerModelNyID mm, StringBuffer statusInfo)
  // add details about MarkerModel object to status info string
  {
    if (!mm.isVisible()){
      statusInfo.append(" not visible\n");
//      System.out.println(" not visible\n");
    }
    else {   // model is visible, so report position and orientation
      Point3d pos = mm.getPos();
      if (pos != null){
        statusInfo.append("    at (" + pos.x + ", " + pos.y + ", " + pos.z + ")\n");
//        System.out.println("    at (" + pos.x + ", " + pos.y + ", " + pos.z + ")\n");
      }
      else{
        statusInfo.append("    at an unknown position\n");
//        System.out.println("    at an unknown position\n");
      }
      Point3d rots = mm.getRots();
      if (rots != null){
        statusInfo.append("    rots (" + rots.x + ", " + rots.y + ", " + rots.z + ")\n");
//        System.out.println("    rots (" + rots.x + ", " + rots.y + ", " + rots.z + ")\n");
      }
      else{
        statusInfo.append("    with unknown rotations\n");
//        System.out.println("    with unknown rotations\n");
      }
    }
  }  // end of addToStatusInfo()

    public void setNumGroupModel(int numGroupModel) {
        this.numGroupModel = numGroupModel;
    }

    public int getNumGroupModel() {
        return numGroupModel;
    }

    public void getMarkerFromGroup(int i_no, int o_idx_MG, int o_idx_mm){
        int i = 0;
        int idx = i_no;
        while (idx > markerGroups.get(i).getNumMarker()){
            idx = idx - markerGroups.get(i).getNumMarker();
            i++;
        }
        o_idx_MG = i;
        o_idx_mm = idx;

    }

    public void setPointer(int pointer) {
        this.pointer1 = pointer;
    }

    public void setPointer2(int pointer2) {
        this.pointer2 = pointer2;
    }
    
}  // end of class DetectMarkersNyID
